package net.oschina.simpleplus.proto2javabean;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;

import com.google.protobuf.GeneratedMessageV3;

import net.oschina.simpleplus.entity.Protobuf;
import net.oschina.simpleplus.entity.test.TestGenJavaBeanMessage4;
import net.oschina.simpleplus.gen.JavaBeanEntity;
import net.oschina.simpleplus.proto.IMessage.JavaBeanMessage;
import net.oschina.simpleplus.proto.IMessage.ParentJavaBeanMessage;
import net.oschina.simpleplus.proto.IMessage.ParentJavaBeanMessage1;
import net.oschina.simpleplus.util.ScanUtil;

public class App {
	public static void main(String[] args) {
//		JavaBeanEntity javaBeanEntity = new JavaBeanEntity(null, "net.oschina.simpleplus.entity.test", "TestGenJavaBeanMessage4", JavaBeanMessage.class);
//		javaBeanEntity.parse();
//		javaBeanEntity.generate();
//	   ArrayList<Integer> arrayList = new ArrayList<Integer>();
//	   Class class1 = TestGenJavaBeanMessage4.class;
////	   
//	   ParameterizedType parameterizedType = (ParameterizedType)class1.getGenericInterfaces()[0];
//	Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
//	System.out.println(actualTypeArguments[0]);
//	   System.out.println(class1.getTypeName());
//		Field[] fs = JavaBeanMessage.class.getDeclaredFields();
//		for (Field field : fs) {
//			String name = field.getName();
//			if(!name.endsWith("_")){
//				continue;
//			}
//			name = name.substring(0, name.lastIndexOf('_'));
//			Class<?> type = field.getType();
//			if(List.class.isAssignableFrom(type)){
//				try {
//					Method m =  JavaBeanMessage.class.getMethod("get"+StringUtils.capitalize(name), int.class);
//					
//					String canonicalName = m.getReturnType().getCanonicalName();
//					System.out.println(name+":"+canonicalName);
//				} catch (NoSuchMethodException e) {
//					// TODO Auto-generated catch block
//					e.printStackTrace();
//				} catch (SecurityException e) {
//					// TODO Auto-generated catch block
//					e.printStackTrace();
//				}
//			}
//		}
		
		
		
//		List<Class<? extends GeneratedMessageV3>> clses = new ArrayList<Class<? extends GeneratedMessageV3>>();
//		
//		clses.add(ParentJavaBeanMessage.class);
//		clses.add(JavaBeanMessage.class);
//		
		Map<Class<?>, String> clsMap = new HashMap<Class<?>, String>();
		
		Set<Class<?>> sets = ScanUtil.getClasses("net.oschina.simpleplus.entity");

		Set<Class<?>> sets1 = ScanUtil.getClasses("net.oschina.simpleplus.proto");
		
		
		TreeSet<Class<? extends GeneratedMessageV3>> treeSet = new TreeSet<Class<? extends GeneratedMessageV3>>(new Comparator<Class<? extends GeneratedMessageV3>>() {
			
			@Override
			public int compare(Class<? extends GeneratedMessageV3> o1, Class<? extends GeneratedMessageV3> o2) {
				if(o1.equals(o2)){
					return 0;
				}
				try{
					
					if(contains0(o1, o2)){
						return 1;
					}
					if(contains0(o2, o1)){
						return -1;
					}
				}catch(Exception e){
					e.printStackTrace();
				}
				
				return 0;
			}
		});
		
		for(Class<?> cls : sets){
			if(cls.isInterface() || cls.isAnonymousClass() || Modifier.isAbstract(cls.getModifiers())){
				continue;
			}
			
			if(!Protobuf.class.isAssignableFrom(cls)){
				continue;
			}
			
			clsMap.put(findParameterizedType(cls), cls.getName());
		}
		
		sets.removeAll(clsMap.values());
		
		for(Iterator<Class<?>> iterator = sets1.iterator(); iterator.hasNext();){
			Class<?> next = iterator.next();
			if(!GeneratedMessageV3.class.isAssignableFrom(next)){
				iterator.remove();
			}
			
			treeSet.add((Class<? extends GeneratedMessageV3>) next);
		}
		clsMap.put(JavaBeanMessage.class, TestGenJavaBeanMessage4.class.getName());
		JavaBeanEntity javaBeanEntity = new JavaBeanEntity(null, "net.oschina.simpleplus.entity.test", "TestGenJavaBeanMessage6", ParentJavaBeanMessage1.class, clsMap);
		javaBeanEntity.parse();
		javaBeanEntity.generate();
	}
	
	private static Class findParameterizedType(Class cls){
		ParameterizedType parameterizedType = (ParameterizedType)cls.getGenericInterfaces()[0];
		return (Class) parameterizedType.getActualTypeArguments()[0];
	}

	private static boolean contains0(Class<? extends GeneratedMessageV3> bigger,
			Class<? extends GeneratedMessageV3> smaller) throws NoSuchMethodException {
		Field[] fs = bigger.getDeclaredFields();
		for(Field f : fs){
			String name = f.getName();
			if(!name.endsWith("_") || "bitField0_".equals(name)){
				continue;
			}
			
			name = name.substring(0, name.lastIndexOf('_'));
			if(smaller.equals(f.getType())){
				return true;
			}
			if(List.class.isAssignableFrom(f.getType())){
				Class<?> returnType = bigger.getMethod("get"+StringUtils.capitalize(name), int.class).getReturnType();
				if(smaller.equals(returnType)){
					return true;
				}
			}
		}
		return false;
	}

}
